home *** CD-ROM | disk | FTP | other *** search
/ Giga Games 1 / Giga Games.iso / net / hack / 3_1_3 / sys / amiga / amisnd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-02-28  |  7.2 KB  |  286 lines

  1. /*    SCCS Id: @(#)amisnd.c    3.1    92/11/28    */
  2. /*     Copyright (c) 1992, 1993 by Gregg Wonderly */
  3. /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5. /*
  6.  * This file contains music playing code.
  7.  *
  8.  * If we were REALLY determined, we would make the sound play
  9.  * asynchronously, but I'll save that one for a rainy day...
  10.  */
  11.  
  12. #include "hack.h"
  13.  
  14. #undef red
  15. #undef blue
  16. #undef green
  17. #include <exec/types.h>
  18. #include <exec/memory.h>
  19. #include <exec/io.h>
  20. #include <devices/audio.h>
  21. #include <dos/dos.h>
  22. #include <dos/dosextens.h>
  23. #include <graphics/gfxbase.h>
  24.  
  25. #include <clib/exec_protos.h>
  26. #include <clib/alib_protos.h>
  27. #include <clib/dos_protos.h>
  28. #include <clib/graphics_protos.h>
  29.  
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32.  
  33. #define    AMII_AVERAGE_VOLUME    60
  34.  
  35. int amii_volume = AMII_AVERAGE_VOLUME;
  36.  
  37. typedef struct VHDR
  38. {
  39.     char name[4];
  40.     long len;
  41.     unsigned long oneshot, repeat, samples;
  42.     UWORD freq;
  43.     UBYTE n_octaves, compress;
  44.     LONG volume;
  45. } VHDR;
  46.  
  47. typedef struct IFFHEAD
  48. {
  49.     char FORM[4];
  50.     long flen;
  51.     char _8SVX[4];
  52.     VHDR vhdr;
  53.     char NAME[4];
  54.     long namelen;
  55. } IFFHEAD;
  56.  
  57. extern struct GfxBase *GfxBase;
  58.  
  59. UBYTE whichannel[] = { 1, 2, 4, 8 };
  60. void makesound( char *, char *, int vol);
  61. void amii_speaker( struct obj *instr, char *melody, int vol );
  62.  
  63. /* A major scale in indexs to freqtab... */
  64. int notetab[] = { 0, 2, 4, 5, 7, 9, 11, 12 };
  65.  
  66. /* Frequencies for a scale starting at one octave below 'middle C' */
  67. long freqtab[] = {
  68.     220,    /*A */
  69.     233,    /*Bb*/
  70.     246,    /*B */
  71.     261,    /*C */
  72.     277,    /*Db*/
  73.     293,    /*D */
  74.     311,    /*Eb*/
  75.     329,    /*E */
  76.     349,    /*F */
  77.     370,    /*Gb*/
  78.     392,    /*G */
  79.     415,    /*Ab*/
  80.     440,    /*A */
  81. };
  82.  
  83. #ifdef    TESTING
  84. main( argc, argv )
  85.     int argc;
  86.     char **argv;
  87. {
  88.     makesound( "wooden_flute", "AwBwCwDwEwFwGwawbwcwdwewfwgw", 60 );
  89.     makesound( "wooden_flute", "AhBhChDhEhFhGhahbhchdhehfhgh", 60 );
  90.     makesound( "wooden_flute", "AqBqCqDqEqFqGqaqbqcqdqeqfqgq", 60 );
  91.     makesound( "wooden_flute", "AeBeCeDeEeFeGeaebecedeeefege", 60 );
  92.     makesound( "wooden_flute", "AxBxCxDxExFxGxaxbxcxdxexfxgx", 60 );
  93.     makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
  94.     makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
  95.     makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
  96.     makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
  97.     makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
  98.     makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
  99.     makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
  100.     makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
  101.     makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
  102. }
  103. #else
  104. void
  105. amii_speaker( struct obj *instr, char *melody, int vol )
  106. {
  107.     int typ = instr->otyp;
  108.     const char * actualn = OBJ_NAME( objects[typ] ) ;
  109.  
  110.     /* Make volume be relative to users volume level, with 60 being the
  111.      * average level that will be passed to us.
  112.      */
  113.     vol = vol * amii_volume / AMII_AVERAGE_VOLUME;
  114.  
  115.     makesound( actualn, melody, vol );
  116. }
  117. #endif
  118.  
  119. void
  120. makesound ( char *actualn , char * melody, int vol )
  121. {
  122.     char *t;
  123.     int c, cycles, dot, dlay;
  124.     FILE *fp = 0;
  125.     IFFHEAD iffhead;
  126.     struct IOAudio *AudioIO = 0;
  127.     struct MsgPort *AudioMP = 0;
  128.     struct Message *AudioMSG = 0;
  129.     ULONG device = -1;
  130.     BYTE *waveptr = 0;
  131.     LONG frequency=440, duration=1, clock, samp, samples, samcyc=1;
  132.     unsigned char name [ 100 ] ;
  133.  
  134.     if ( flags.silent )
  135.         return;
  136.  
  137.     if( GfxBase->DisplayFlags & PAL )
  138.         clock = 3546895;
  139.     else
  140.         clock = 3579545;
  141.  
  142.     /*
  143.      * Is this a known instrument ?
  144.      *
  145.      */
  146.     sprintf ( name, "NetHack:sounds/%s", actualn ) ;
  147.     for( t = strchr( name, ' ' ); t; t = strchr( name, ' ' ) )
  148.         *t = '_';
  149.     if( (fp = fopen( name, "r" )) == NULL )
  150.     {
  151.         if((fp=fopen(&name[15],"r"))==NULL){
  152.         perror( name );
  153.         return;
  154.         }
  155.     }
  156.  
  157.     AudioIO = (struct IOAudio *)
  158.         AllocMem( sizeof( struct IOAudio ), MEMF_PUBLIC|MEMF_CLEAR );
  159.     if( AudioIO == 0 )
  160.         goto killaudio;
  161.  
  162.     AudioMP = CreatePort( NULL, 0 );
  163.     if( AudioMP == 0 )
  164.         goto killaudio;
  165.  
  166.     AudioIO->ioa_Request.io_Message.mn_ReplyPort = AudioMP;
  167.     AudioIO->ioa_Request.io_Message.mn_Node.ln_Pri = 0;
  168.     AudioIO->ioa_Request.io_Command = ADCMD_ALLOCATE;
  169.     AudioIO->ioa_Request.io_Flags = ADIOF_NOWAIT;
  170.     AudioIO->ioa_AllocKey = 0;
  171.     AudioIO->ioa_Data = whichannel;
  172.     AudioIO->ioa_Length = sizeof( whichannel );
  173.  
  174.     device = OpenDevice( AUDIONAME, 0L, (struct IORequest *)AudioIO, 0L );
  175.     if( device != 0 )
  176.         goto killaudio;
  177.  
  178.     if( fread( &iffhead, sizeof( iffhead ), 1, fp ) != 1 )
  179.         goto killaudio;
  180.  
  181.     /* This is an even number of bytes long */
  182.     if( fread( name, (iffhead.namelen+1) & ~1, 1, fp ) != 1 )
  183.         goto killaudio;
  184.  
  185.     if( fread( &samples, 4, 1, fp ) != 1 )
  186.         goto killaudio;
  187.  
  188.     if( fread( &samples, 4, 1, fp ) != 1 )
  189.         goto killaudio;
  190.  
  191.     waveptr = AllocMem( samples, MEMF_CHIP|MEMF_PUBLIC );
  192.     if( !waveptr )
  193.         goto killaudio;
  194.  
  195.     if( fread( waveptr, samples, 1, fp ) != 1 )
  196.         goto killaudio;
  197.  
  198.     while( melody[0] && melody[1] )
  199.     {
  200.         c = *melody++;
  201.         duration = *melody++;
  202.         dot = 0;
  203.         if( *melody == '.' )
  204.         {
  205.             dot = 1;
  206.             ++melody;
  207.         }
  208.         switch( duration )
  209.         {
  210.             case 'w': dlay = 3; duration = 1; cycles = 1; break;
  211.             case 'h': dlay = 3; duration = 2; cycles = 1; break;
  212.             case 'q': dlay = 2; duration = 4; cycles = 1; break;
  213.             case 'e': dlay = 1; duration = 8; cycles = 1; break;
  214.             case 'x': dlay = 0; duration = 16; cycles = 1; break;
  215.             case 't': dlay = 0; duration = 32; cycles = 1; break;
  216.             default: goto killaudio;  /* unrecognized duration */
  217.         }
  218.  
  219.         /* Lower case characters are one octave above upper case */
  220.         switch( c )
  221.         {
  222.             case 'a': case 'b': case 'c':
  223.             case 'd': case 'e': case 'f': case 'g':
  224.                 c -= 'a' - 7;
  225.                 break;
  226.  
  227.             case 'A': case 'B': case 'C':
  228.             case 'D': case 'E': case 'F': case 'G':
  229.                 c -= 'A';
  230.                 break;
  231.  
  232.             default:
  233.                 continue;
  234.         }
  235.  
  236.         samcyc = samples;
  237.  
  238.         /* lowercase start at middle 'C', upper case are one octave below */
  239.         frequency = c > 7 ? freqtab[notetab[c%7]]*2 : freqtab[notetab[c]];
  240.  
  241.         /* We can't actually do a dotted whole note unless we add code for a real
  242.          * 8SVX sample which includes sustain sample information to tell us how
  243.          * to hold the note steady...  So when duration == 1, ignore 'dot'...
  244.          */
  245.         if( dot && duration > 1 )
  246.             samp = ((samples / duration) * 3) / 2;
  247.         else
  248.             samp = samples / duration;
  249.  
  250.         /* Only use some of the samples based on frequency */
  251.         samp = frequency * samp / 880;
  252.  
  253.         /* The 22khz samples are middle C samples, so adjust the play
  254.          * back frequency accordingly
  255.          */
  256.         frequency = (frequency * (iffhead.vhdr.freq*2)/3) / 440L;
  257.  
  258.         AudioIO->ioa_Request.io_Message.mn_ReplyPort = AudioMP;
  259.         AudioIO->ioa_Request.io_Command = CMD_WRITE;
  260.         AudioIO->ioa_Request.io_Flags = ADIOF_PERVOL;
  261.         AudioIO->ioa_Data = (BYTE *)waveptr;
  262.         AudioIO->ioa_Length = samp;
  263.  
  264.         /* The clock rate represents the unity rate, so dividing by
  265.          * the frequency gives us a period ratio...
  266.          */
  267. /*printf( "clock: %ld, freq: %ld, div: %ld\n", clock, frequency, clock/frequency );*/
  268.         AudioIO->ioa_Period = clock/frequency;
  269.         AudioIO->ioa_Volume = vol;
  270.         AudioIO->ioa_Cycles = cycles;
  271.  
  272.         BeginIO( (struct IORequest *)AudioIO );
  273.         WaitPort( AudioMP );
  274.         AudioMSG = GetMsg( AudioMP );
  275.         if( dlay )
  276.             Delay( dlay );
  277.     }
  278.  
  279.     killaudio:
  280.     if( fp ) fclose( fp );
  281.     if( waveptr ) FreeMem( waveptr, samples );
  282.     if( device == 0 ) CloseDevice( (struct IORequest *)AudioIO );
  283.     if( AudioMP ) DeletePort( AudioMP );
  284.     if( AudioIO ) FreeMem( AudioIO, sizeof( *AudioIO ) );
  285. }
  286.